import { IdCard } from "./entity/IdCard";
import { User } from "./entity/User";
import { DataSource } from "typeorm"; 

export async function one2one(AppDataSource: DataSource) {
  console.log("Inserting a new user into the database...");
  const user = new User();
  user.firstName = "Timber";
  user.lastName = "Saw";
  user.age = 25;
  await AppDataSource.manager.save(user);
  console.log("Saved a new user with id: " + user.id);

  console.log("Loading users from the database...");
  const users = await AppDataSource.manager.find(User);
  console.log("Loaded users: ", users);

  await AppDataSource.manager.save(User, [
    { firstName: "ccc", lastName: "ccc", age: 21 },
    { firstName: "ddd", lastName: "ddd", age: 22 },
    { firstName: "eee", lastName: "eee", age: 23 },
  ]);
  const users2 = await AppDataSource.manager.find(User);
  console.log("insert batch users success: ", users2);

  await AppDataSource.manager.save(User, [
    { id: 2, firstName: "ccc111", lastName: "ccc", age: 21 },
    { id: 3, firstName: "ddd222", lastName: "ddd", age: 22 },
    { id: 4, firstName: "eee333", lastName: "eee", age: 23 },
  ]);
  const users3 = await AppDataSource.manager.find(User);
  console.log("update batch users success: ", users3);

  //其实 EntityManager 还有 update 和 insert 方法，分别是修改和插入的，但是
  //它们不会先 select 查询一次。而 save 方法会先查询一次数据库来确定是插入还是修改。

  await AppDataSource.manager.update(
    User,
    { id: 2 },
    {
      firstName: "Timber111",
      lastName: "Saw111",
      age: 25,
    }
  );
  const users344 = await AppDataSource.manager.find(User);
  console.log("update users success: ", users344);

  await AppDataSource.manager.insert(User, {
    firstName: "xx",
    lastName: "xx",
    age: 25,
  });
  const users55 = await AppDataSource.manager.find(User);
  console.log("insert users success: ", users55);

  // await AppDataSource.manager.delete(User, 1);
  // await AppDataSource.manager.delete(User, [2, 3]);
  // const usera = new User();
  // usera.id = 1;
  // await AppDataSource.manager.remove(User, user);
  // //delete 和 remove 的区别是，delete 直接传 id、而 remove 则是传入 entity 对象。
  // console.log("remove batch users success: ", [1, 2, 3]);

  // findBy
  await AppDataSource.manager.findBy(User, {
    firstName: "xx",
  });
  // findAndCount
  const users4 = await AppDataSource.manager.findAndCount(User, {
    where: {
      age: 25,
    },
  });
  console.log(users4);

  // findAndCountBy
  const users5 = await AppDataSource.manager.findAndCountBy(User, {
    age: 25,
  });
  console.log(users5);

  //findOne
  const user6 = await AppDataSource.manager.findOne(User, {
    where: {
      age: 25,
    },
    order: {
      id: "ASC",
    },
  });
  console.log(user6);

  //findOneBy
  const user7 = await AppDataSource.manager.findOneBy(User, {
    age: 25,
  });
  console.log(user7);

  // findOneOrFail 或者 findOneByOrFail，如果没找到，会抛一个 EntityNotFoundError 的异常
  try {
    const user = await AppDataSource.manager.findOneOrFail(User, {
      where: {
        id: 666,
      },
    });
    console.log(user);
  } catch (e) {
    console.log(e);
    console.log("没找到该用户");
  }

  //你还可以用 query 方法直接执行 sql 语句

  const users23 = await AppDataSource.manager.query(
    "select * from user where age in(?, ?)",
    [31, 31]
  );
  console.log(users23);
  //但复杂 sql 语句不会直接写，而是会用 query builder：
  const queryBuilder = await AppDataSource.manager.createQueryBuilder(); //：创建复杂 sql 语句，比如 join 多个 Entity 的查询
  const user22 = await queryBuilder
    .select("user")
    .from(User, "user")
    .where("user.age = :age", { age: 21 })
    .getOne();

  console.log(11, user22);

  // transaction 包裹一层事务的 sql
  await AppDataSource.manager.transaction(async (manager) => {
    await manager.save(User, {
      id: 4,
      firstName: "eee",
      lastName: "eee",
      age: 20,
    });
  });

  // getRepository AppDataSource.manager  区别？
  // getRepository 是直接获取 Entity 的 Repository 对象，而 AppDataSource.manager 是先获取 EntityManager 对象，再调用它的 getRepository 方法。
  // 所以，AppDataSource.manager 更加强大，因为它可以直接执行 sql 语句，而 getRepository 只能执行 Repository 定义的方法。

  // getRepository ：获取 Entity 的 Repository 对象，用于操作数据库
  const userRepository = AppDataSource.manager.getRepository(User);
  const user2 = await userRepository.findOne({
    where: {
      id: 4,
    },
  });
  console.log(22, user2);

  const userLink = new User();
  userLink.firstName = "ss";
  userLink.lastName = "ss";
  userLink.age = 20;

  const idCard = new IdCard();
  idCard.cardName = "1111111";
  idCard.user = userLink;

  // await AppDataSource.manager.save(user);
  await AppDataSource.manager.save(idCard);

  const ics = await AppDataSource.manager.find(IdCard, {
    relations: {
      user: true, // 加载 user 实体
    },
  });

  console.log("ics:", ics);

  const user117 = await AppDataSource.manager.findOne(User, {
    where: {
      id: 117,
    },
  });

  console.log("user117:", user117);

  const ics2 = await AppDataSource.manager
    .getRepository(IdCard)
    .createQueryBuilder("ic")
    .leftJoinAndSelect("ic.user", "u")
    .getMany();

  console.log(44, ics2);

  const ics3 = await AppDataSource.manager.query(`SELECT ic.*, u.* 
FROM id_card ic 
LEFT JOIN user u ON ic.user_id = u.id;`);

  console.log(55, ics3);

  await AppDataSource.manager.delete(IdCard, { id: 4 }); // 删除 id 为 4 的 id_card 实体， 因cascade 关系，会同时删除 user 实体
}
